namespace SimpleWebServices.Web.UI.Html.Elements
{
    using System.Xml.Serialization;
    using System.Xml.XPath;
    using SimpleWebServices;
    using Xunit;

    public sealed class SelectFacts
    {
        [Fact]
        public void typedef()
        {
            Assert.True(new ObjectExpectations<Select>()
                .DerivesFrom<Control>()
                .IsConcreteClass()
                .IsUnsealed()
                .HasDefaultConstructor()
                .Implements<IXmlSerializable>()
                .XmlRoot("select")
                .Result);
        }

        [Fact]
        public void deserialize()
        {
            Select expected = new Select(new Name("id"))
            {
                Class = "class",
                Disabled = true,
                Language = "fr",
                MultipleSelections = true,
                RowsVisible = 10,
                TabIndex = 1
            };

            string xml = "<select id='id' class='class' lang='fr' name='id' disabled='disabled' multiple='multiple' size='10' tabindex='1'><foo /></select>";
            Select actual = xml.Deserialize<Select>();

            Assert.Equal<string>(expected.ToString(), actual.ToString());
        }

        [Fact]
        public void deserializeEmpty()
        {
            Assert.NotNull("<select />".Deserialize<Select>());
        }

        [Fact]
        public void serialize()
        {
            Select obj = new Select(new Name("id"))
            {
                Class = "class",
                Disabled = true,
                Language = "fr",
                MultipleSelections = true,
                RowsVisible = 10,
                TabIndex = 1
            };

            string xpath = "1=count(/select[@id='id'][@class='class'][@lang='fr'][@name='id'][@tabindex='1'][@disabled='disabled'][@multiple='multiple'][@size='10'])";

            Assert.True((bool)obj.Serialize().CreateNavigator().Evaluate(xpath));
        }

        [Fact]
        public void ctor()
        {
            Assert.NotNull(new Select());
        }

        [Fact]
        public void ctor_Name()
        {
            Assert.NotNull(new Select(new Name("id")));
        }

        [Fact]
        public void ctor_NameNull()
        {
            Assert.NotNull(new Select(null));
        }

        [Fact]
        public void prop_MultipleSelections()
        {
            Assert.True(new PropertyExpectations(typeof(Select).GetProperty("MultipleSelections"))
                .IsAutoProperty<bool>()
                .Result);
        }

        [Fact]
        public void prop_Options()
        {
            Assert.True(new PropertyExpectations(typeof(Select).GetProperty("Options"))
                .DefaultValueIsNotNull()
                .Result);
        }

        [Fact]
        public void prop_RowsVisible()
        {
            Assert.True(new PropertyExpectations(typeof(Select).GetProperty("RowsVisible"))
                .IsAutoProperty<int?>()
                .Result);
        }

        [Fact]
        public void prop_Value_getOption()
        {
            string expected = "value";

            Select obj = new Select
            {
                Options =
                {
                    new Option() { Selected = true, Text = "text", Value = expected }
                }
            };

            string actual = obj.Value;

            Assert.Equal<string>(expected, actual);
        }

        [Fact]
        public void prop_Value_getOptionGroup()
        {
            string expected = "value2.2";

            Select obj = new Select
            {
                Options =
                {
                    new Option() { Text = "text1", Value = "value1" },
                    new OptionGroup
                    {
                        Label = "label",
                        Options =
                        {
                            new Option() { Text = "text2.1", Value = "value2.1" },
                            new Option() { Selected = true, Text = "text2.2", Value = expected }
                        }
                    },
                    new Option() { Text = "text3", Value = "value3" }
                }
            };

            string actual = obj.Value;

            Assert.Equal<string>(expected, actual);
        }

        [Fact]
        public void prop_Value_setOption()
        {
            Select obj = new Select
            {
                Options =
                {
                    new Option() { Text = "text", Value = "value" }
                },
                Value = "value"
            };

            Assert.True((obj.Options[0] as Option).Selected);
        }

        [Fact]
        public void prop_Value_setOptionGroup()
        {
            Select obj = new Select
            {
                Options =
                {
                    new Option() { Text = "text1", Value = "value1" },
                    new OptionGroup
                    {
                        Label = "label",
                        Options =
                        {
                            new Option() { Selected = true, Text = "text2.1", Value = "value2.1" },
                            new Option() { Text = "text2.2", Value = "value2.2" }
                        }
                    },
                    new Option() { Text = "text3", Value = "value3" }
                },
                Value = "value2.2"
            };

            Assert.False((obj.Options[1] as OptionGroup).Options[0].Selected);
            Assert.True((obj.Options[1] as OptionGroup).Options[1].Selected);
        }

        [Fact]
        public void op_Contains_string()
        {
            string xml =
                "<select id='id' name='id'>" +
                    "<option value='value1'>text1</option>" +
                    "<optgroup label='label' >" +
                        "<option value='value2.1'>text2.1</option>" +
                        "<option value='value2.2'>text2.2</option>" +
                    "</optgroup>" +
                    "<option value='value3' selected='selected'>text3</option>" +
                "</select>";
            Select obj = xml.Deserialize<Select>();

            Assert.True(obj.Contains("value1"));
            Assert.True(obj.Contains("value2.2"));
        }

        [Fact]
        public void op_Contains_stringMissing()
        {
            string xml =
                "<select id='id' name='id'>" +
                    "<option value='value1'>text1</option>" +
                    "<optgroup label='label' >" +
                        "<option value='value2.1'>text2.1</option>" +
                        "<option value='value2.2'>text2.2</option>" +
                    "</optgroup>" +
                    "<option value='value3' selected='selected'>text3</option>" +
                "</select>";
            Select obj = xml.Deserialize<Select>();

            Assert.False(obj.Contains("missing"));
        }

        [Fact]
        public void op_Contains_stringEmpty()
        {
            string xml =
                "<select id='id' name='id'>" +
                    "<option value='value1'>text1</option>" +
                    "<optgroup label='label' >" +
                        "<option value='value2.1'>text2.1</option>" +
                        "<option value='value2.2'>text2.2</option>" +
                    "</optgroup>" +
                    "<option value='value3' selected='selected'>text3</option>" +
                "</select>";
            Select obj = xml.Deserialize<Select>();

            Assert.False(obj.Contains(string.Empty));
        }

        [Fact]
        public void op_Contains_stringNull()
        {
            Assert.False(new Select().Contains(null));
        }

        [Fact]
        public void op_Deserialize_string_string_string()
        {
            Select expected = new Select(new Name("id"))
            {
                Options =
                {
                    new Option() { Text = "text1", Value = "value1" },
                    new OptionGroup
                    {
                        Label = "label",
                        Options =
                        {
                            new Option() { Text = "text2.1", Value = "value2.1" },
                            new Option() { Text = "text2.2", Value = "value2.2" }
                        }
                    },
                    new Option() { Selected = true, Text = "text3", Value = "value3" }
                }
            };

            string xml =
                "<select id='id' name='id'>" +
                    "<option value='value1'>text1</option>" +
                    "<optgroup label='label' >" +
                        "<option value='value2.1'>text2.1</option>" +
                        "<option value='value2.2'>text2.2</option>" +
                    "</optgroup>" +
                    "<option value='value3' selected='selected'>text3</option>" +
                "</select>";
            Select actual = new Select().Deserialize("select", null, xml) as Select;

            Assert.Equal<string>(expected.ToString(), actual.ToString());
        }

        [Fact]
        public void IXmlSerializable_op_ReadXml_XmlReaderCollection()
        {
            Select expected = new Select(new Name("id"))
            {
                Options =
                {
                    new Option() { Text = "text1", Value = "value1" },
                    new OptionGroup
                    {
                        Label = "label",
                        Options =
                        {
                            new Option() { Text = "text2.1", Value = "value2.1" },
                            new Option() { Text = "text2.2", Value = "value2.2" }
                        }
                    },
                    new Option() { Selected = true, Text = "text3", Value = "value3" }
                }
            };

            string xml =
                "<select id='id' name='id'>" +
                    "<option value='value1'>text1</option>" +
                    "<optgroup label='label' >" +
                        "<option value='value2.1'>text2.1</option>" +
                        "<option value='value2.2'>text2.2</option>" +
                    "</optgroup>" +
                    "<option value='value3' selected='selected'>text3</option>" +
                "</select>";
            Select actual = xml.Deserialize<Select>();

            Assert.Equal<string>(expected.ToString(), actual.ToString());
        }

        [Fact]
        public void IXmlSerializable_op_WriteXml_XmlWriterCollection()
        {
            Select obj = new Select(new Name("name"))
            {
                Options =
                {
                    new Option() { Text = "text1", Value = "value1" },
                    new OptionGroup
                    {
                        Label = "label",
                        Options =
                        {
                            new Option() { Text = "text2", Value = "value2" }
                        }
                    },
                    new Option() { Selected = true, Text = "text3", Value = "value3" }
                }
            };

            XPathNavigator navigator = obj.Serialize().CreateNavigator();
            Assert.True((bool)navigator.Evaluate("1=count(/select[@id='name']/option[@value='value1'])"));
            Assert.True((bool)navigator.Evaluate("1=count(/select[@id='name']/optgroup[@label='label']/option[@value='value2'])"));
            Assert.True((bool)navigator.Evaluate("1=count(/select[@id='name']/option[@value='value3'][@selected='selected'])"));
        }
    }
}